#include <stdint.h>

#define UART0_BASE 0x10009000
#define UARTFR (0x18/4)
#define UARTFR_TXFF 0x20
#define UARTFR_RXFE 0x10

#define UARTDR 0x00
#define UARTIBRD (0x24 /4)
#define UARTFBRD (0x28 /4)
#define UARTLCR_H (0x2C /4)
#define UARTCR (0x30 /4)

#define FB_ADDR 0x00100000
#define FB_WIDTH 640
#define FB_HEIGHT 480
#define FB_DEPTH 32


//uart0 设置波特率 115200，8位数据位，1位停止位，无校验位
void uart_init() {
    volatile uint32_t *uart0 = (uint32_t *)UART0_BASE;
    // 禁用 UART
    uart0[UARTCR] = 0x0;

    // 设置波特率 115200
    // 假设 UART 时钟为 24 MHz
    uint32_t baud_divisor = 24000000 / (16 * 115200);
    uart0[UARTIBRD] = baud_divisor;
    uart0[UARTFBRD] = (24000000 % (16 * 115200)) * 64 / (16 * 115200);

    // 设置 8位数据位，1位停止位，无校验位
    uart0[UARTLCR_H] = (1 << 5) | (1 << 6);

    // 启用 UART，TX 和 RX
    uart0[UARTCR] = (1 << 0) | (1 << 8) | (1 << 9);
}

void uart_putc(char c) {
    volatile uint32_t *uart0 = (uint32_t *)UART0_BASE;
    while (uart0[UARTFR] & UARTFR_TXFF); // 等待直到 TX FIFO 不满
    uart0[UARTDR] = c;
}

void uart_puts(const char *str) {
    while (*str) {
        uart_putc(*str++);
    }
}

void uart_puthex(uint32_t val) {
    const char *hex = "0123456789ABCDEF";
    for (int i = 28; i >= 0; i -= 4) {
        uart_putc(hex[(val >> i) & 0xF]);
    }
}


void uart_getc(char *c) {
    volatile uint32_t *uart0 = (uint32_t *)UART0_BASE;
    while(uart0[UARTFR] & UARTFR_RXFE); // 等待直到 RX FIFO 不空
    *c = uart0[UARTDR];
}


#define PL110_BASE 0x10020000
#define PL110_LCD_TIMING0 (*(volatile uint32_t *)(PL110_BASE + 0x00))
#define PL110_LCD_TIMING1 (*(volatile uint32_t *)(PL110_BASE + 0x04))
#define PL110_LCD_TIMING2 (*(volatile uint32_t *)(PL110_BASE + 0x08))
#define PL110_LCD_TIMING3 (*(volatile uint32_t *)(PL110_BASE + 0x0C))
#define PL110_LCD_UPBASE  (*(volatile uint32_t *)(PL110_BASE + 0x10))
#define PL110_LCD_CONTROL (*(volatile uint32_t *)(PL110_BASE + 0x18))

void pl110_init() {
    // 设置帧缓冲区地址和大小
    uint32_t *framebuffer = (uint32_t *)FB_ADDR;
    for (int y = 0; y < FB_HEIGHT; y++) {
        for (int x = 0; x < FB_WIDTH; x++) {
            framebuffer[y * FB_WIDTH + x] = 0x000000; // 初始化为黑色
        }
    }


    // 配置 PL110 寄存器
    PL110_LCD_TIMING0 = 0x3F1F3F9C; // 配置时序寄存器0
    PL110_LCD_TIMING1 = 0x090B61DF; // 配置时序寄存器1
    PL110_LCD_TIMING2 = 0x067F1800; // 配置时序寄存器2
    PL110_LCD_UPBASE = FB_ADDR;     // 设置帧缓冲区地址
    PL110_LCD_CONTROL = 0x192B;     // 启用 LCD 控制器

    // 启用显示输出
    PL110_LCD_CONTROL |= 0x0001; // 启用 LCD
}



void draw_pixel(int x, int y, uint32_t color) {
    uint32_t *fb = (uint32_t *)FB_ADDR;
    fb[y * FB_WIDTH + x] = color;
}


extern unsigned char ascfont[128][8];  //简单的asc字符的字体，个字符是8x8像素,从 asc 32 开始 到 126

void draw_char(int x, int y, char c, uint32_t color) {
    // 简单的字符绘制函数，假设每个字符是8x8像素
    // 这里只是一个示例，实际需要一个字体表
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if ( (c >= 32) && (ascfont[(int)c - 32][i] & (1 << j)) )
                draw_pixel(x + i, y + j, color);
            else
                draw_pixel(x + i, y + j, 0x000000); // 黑色
        }
    }
}

void draw_string(int x, int y, const char *str, uint32_t color) {
    while (*str) {
        draw_char(x, y, *str++, color);
        x += 8; // 假设每个字符宽度为8像素
    }
}


void draw_rect(int x, int y, int w, int h, uint32_t color) {
    for (int i = x; i < x + w; i++) {
        for (int j = y; j < y + h; j++) {
            draw_pixel(i, j, color);
        }
    }
}

void draw_circle(int x, int y, int r, uint32_t color) {
    for (int i = x - r; i < x + r; i++) {
        for (int j = y - r; j < y + r; j++) {
            if ((i - x) * (i - x) + (j - y) * (j - y) < r * r) {
                draw_pixel(i, j, color);
            }
        }
    }
}

void main() {
    uart_init();
    uart_puts("UART initialized.\n");

    pl110_init();
    uart_puts("PL110 initialized.\n");

    // 清屏
    for (int y = 0; y < FB_HEIGHT; y++) {
        for (int x = 0; x < FB_WIDTH; x++) {
            draw_pixel(x, y, 0x000000); // 黑色
        }
    }

    uart_puts("Screen cleared.\n");

    // 打印文字
    draw_string(10, 10, "Hello, RealView PBX-A9!", 0xFFFFFF); // 白色

    draw_rect(100, 100, 200, 200, 0xFF0000); // 红色
    draw_circle(300, 300, 100, 0x00FF00); // 绿色

    uart_puts("Text drawn on screen.\n");

    int x = 0, y = 400;
    while (1) {
        char c;
        uart_getc(&c);
        uart_putc(c);
        if (c == '\r') {
            uart_putc('\n');
            y += 8;x = 0;
        }  else {
            draw_char(x, y, c, 0x0000FF); // 蓝色
            x += 8;
        }
    }
}